package com.un.ebs.quality.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.util.DateUtils;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.inventory.domain.InventoryNoteItem;
import com.un.ebs.inventory.domain.InventoryNoteItemExt;
import com.un.ebs.inventory.enums.InventoryTypeEnum;
import com.un.ebs.inventory.mapper.InventoryNoteItemExtMapper;
import com.un.ebs.inventory.mapper.InventoryNoteItemMapper;
import com.un.ebs.inventory.mapper.InventoryNoteMapper;
import com.un.ebs.inventory.service.InventoryNoteService;
import com.un.ebs.production.domain.ProductionWorkOrder;
import com.un.ebs.production.domain.ProductionWorkOrderExt;
import com.un.ebs.production.enums.QualityCheckPlanTypeEnum;
import com.un.ebs.production.mapper.ProductionOrderMapper;
import com.un.ebs.production.mapper.ProductionWorkOrderExtMapper;
import com.un.ebs.production.mapper.ProductionWorkOrderMapper;
import com.un.ebs.production.service.ProductionWorkOrderService;
import com.un.ebs.quality.CostCode;
import com.un.ebs.quality.domain.QualityCheck;
import com.un.ebs.quality.domain.QualityCheckExt;
import com.un.ebs.quality.dto.QualityCheckByInventoryDto;
import com.un.ebs.quality.dto.QualityCheckByProcessDto;
import com.un.ebs.quality.dto.QualityCheckPlanDto;
import com.un.ebs.quality.enums.QualityTypeEnum;
import com.un.ebs.quality.mapper.QualityCheckExtMapper;
import com.un.ebs.quality.mapper.QualityCheckMapper;
import com.un.ebs.quality.service.QualityCheckService;
import com.un.ebs.sys.service.ConfigureService;
import com.un.ebs.sys.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (QualityCheck)表服务实现类
 *
 * @author liubo
 * @since 2020-11-15 20:05:17
 */
@Service("qualityCheckService")
public class QualityCheckServiceImpl extends ServiceImpl<QualityCheckMapper, QualityCheck> implements QualityCheckService {

    @Resource
    private ProductionOrderMapper productionOrderMapper;

    @Resource
    private ProductionWorkOrderService productionWorkOrderService;

    @Resource
    private ProductionWorkOrderExtMapper productionWorkOrderExtMapper;

    @Resource
    private ProductionWorkOrderMapper productionWorkOrderMapper;

    @Resource
    private ConfigureService configureService;

    @Resource
    private InventoryNoteItemExtMapper inventoryNoteItemExtMapper;

    @Resource
    private QualityCheckExtMapper qualityCheckExtMapper;

    @Resource
    private InventoryNoteMapper inventoryNoteMapper;

    @Resource
    private InventoryNoteItemMapper inventoryNoteItemMapper;

    @Resource
    private InventoryNoteService inventoryNoteService;

    @Resource
    private UserService userService;

    @Override
    public void updateCheckPlanByProcess(String productionOrderId, int planCheckQty) {
        for (ProductionWorkOrder item : productionOrderMapper.selectWorkOrderByProductionOrderId(productionOrderId)) {
            item.setPlanCheckQty(new BigDecimal(planCheckQty)
                    .divide(new BigDecimal(item.getPlanWorkQty()))
                    .multiply(new BigDecimal(100))
                    .setScale(0)
                    .doubleValue());
            item.updateById();
        }
    }

    @Override
    public void updateCheckPlanByInventory(String inventoryNoteId, int planCheckQty) {
        for (InventoryNoteItem item : inventoryNoteMapper.selectItemByNoteId(inventoryNoteId)) {
            item.setPlanCheckQty(new BigDecimal(planCheckQty)
                    .divide(new BigDecimal(item.getQty()))
                    .multiply(new BigDecimal(100))
                    .setScale(0)
                    .doubleValue());
            item.updateById();
        }
    }

    @Transactional
    @Override
    public void check(List<QualityCheckByProcessDto> reqs) {
        ProductionWorkOrderExt order = productionWorkOrderService.queryViewById(reqs.get(0).getProductionWorkOrderId());
        for (QualityCheckByProcessDto req : reqs) {
            if (order == null) {
                throw new BusinessEntityNotFoundException(req.getProductionWorkOrderId(), "工序");
            }
            if (!userService.hasRole(order.getRoleId())) {
                throw new BusinessException(String.format("你当前不是【%s】的用户，不能执行此操作。", order.getRoleName()));
            }
            if (StringUtils.isNullOrEmpty(req.getProductionWorkOrderId())) {
                throw new BusinessException("请指定检验工序。");
            }
            if (order.getPlanCheckQty() <= 0) {
                throw new BusinessException("当前工序的计划检验数量是零，不需要检验。");
            }
//        if (order.getRealCheckPassQty() >= order.getPlanCheckQty()) {
//            throw new BusinessException("当前工序已检验完成，不需要检验。");
//        }

            add(null, req.getProductionWorkOrderId(), req.getQualityDefineId(), QualityTypeEnum.ProcessCheck, req.getCheckRemark(), req.getRealCheckQty(), req.getNotPassQty(), req.getPassStatus());
        }

        if (reqs.stream().filter(s -> s.getPassStatus() == false).count() == 0) {
            for (String id : reqs.stream().map(s -> s.getProductionWorkOrderId()).distinct().collect(Collectors.toList())) {
                productionWorkOrderService.complete(id);
            }
        }
    }

    @Transactional
    @Override
    public void check(QualityCheckByInventoryDto req) {
        InventoryNoteItemExt itemView = inventoryNoteService.queryItemByItemId(req.getInventoryNoteItemId());
        if (itemView == null) {
            throw new BusinessEntityNotFoundException(req.getInventoryNoteItemId(), "单据条目");
        }
        if (itemView.getPlanCheckQty() <= 0) {
            throw new BusinessException("当前单据条目的计划检验数量为零，不需要检验。");
        }
        if (itemView.getRealCheckPassQty() >= itemView.getPlanCheckQty()) {
            throw new BusinessException("当前单据条目忆检验完成，不需要检验。");
        }
        if (!req.getPassStatus() && req.getNotPassQty() <= 0) {
            throw new BusinessException("请填写不通过数量。");
        }
        if (req.getRealCheckQty() > itemView.getQty()) {
            throw new BusinessException("实际检验数量不能大于单据原始数量。");
        }
        if (req.getNotPassQty() > itemView.getQty()) {
            throw new BusinessException("未通过数量不能大于单据原始数量。");
        }

        String checkNoteId = add(
                req.getInventoryNoteItemId(),
                null,
                req.getQualityDefineId(),
                itemView.getInventoryType() == InventoryTypeEnum.OUT ? QualityTypeEnum.InventoryOutCheck : QualityTypeEnum.InventoryInCheck,
                req.getRemark(),
                req.getRealCheckQty(),
                req.getNotPassQty(),
                req.getPassStatus()
        );
        if (!req.getPassStatus()) {
            //inventoryNoteService.submitCancel(itemView.getNoteId());
            inventoryNoteService.qualityNotPass(itemView.getId(), req.getNotPassQty(), checkNoteId);
        }
    }

    @Transactional
    @Override
    public void checkPassByProduction(String productionWorkOrderId) {
        ProductionWorkOrder order = productionWorkOrderMapper.selectById(productionWorkOrderId);
        if (order == null) {
            throw new BusinessEntityNotFoundException(productionWorkOrderId, "工单");
        }
        if (order.getCompletedStatus()) {
            throw new BusinessException("不能重复进行完工确认。");
        }
        QualityCheck check = new QualityCheck();
        check.setCheckQty(order.getPlanCheckQty());
        check.setNotPassQty(0d);
        check.setPassStatus(true);
        check.setProductionWorkOrderId(productionWorkOrderId);
        check.setQualityType(QualityTypeEnum.ProcessCheck);
        check.insert();

        productionWorkOrderService.complete(productionWorkOrderId);
    }

    @Override
    public void checkPassByPurchase(String id) {
        InventoryNoteItemExt item = inventoryNoteItemExtMapper.selectById(id);
        if (item == null) {
            throw new BusinessEntityNotFoundException(id, "入库条目");
        }
        if (!item.getSubmitStatus()) {
            throw new BusinessException("采购入库单没有提交。");
        }
        if (item.getAuditStatus()) {
            throw new BusinessException("采购入库单已审核。");
        }

        QualityCheck check = new QualityCheck();
        check.setNotPassQty(0d);
        check.setQualityType(QualityTypeEnum.InventoryInCheck);
        check.setInventoryNoteItemId(id);
        check.setPassStatus(true);
        check.setCheckQty(item.getPlanCheckQty());
        check.insert();

        InventoryNoteItem  obj = inventoryNoteItemMapper.selectById(id);
        obj.setCheckNoteId(check.getId());
        obj.updateById();
    }

    @Override
    public List<QualityCheckPlanDto> queryCheckPlan(String searchText, QualityTypeEnum type) {
        List<QualityCheckPlanDto> result = new ArrayList<>();

        if (type == QualityTypeEnum.Default || type == QualityTypeEnum.ProcessCheck) {
            result.addAll(queryCheckPlanByProduction().stream().map(s -> {
                QualityCheckPlanDto obj = new QualityCheckPlanDto();
                obj.setId(s.getId());
                obj.setCode(s.getProductionOrderCode());
                obj.setType(QualityTypeEnum.ProcessCheck);
                obj.setCheckPlanType(s.getCheckPlanType());
                switch (s.getCheckPlanType()) {
                    case All:
                        obj.setPlanCheckQty(s.getPlanWorkQty());
                        break;
                    case Proportion:
                        obj.setPlanCheckQty(new BigDecimal(s.getPlanWorkQty()).multiply(new BigDecimal(obj.getCheckPlanQty())).divide(new BigDecimal(100)).setScale(0).doubleValue());
                        break;
                    case Ration:
                        obj.setPlanCheckQty(s.getCheckPlanQty().doubleValue());
                        break;
                    default:
                        obj.setPlanCheckQty(0d);
                }
                obj.setRemark(String.format("工序号：%s，检验项目：%s，产品：%s", s.getProductionSeqItemCode(), s.getProductionSeqItemName(), s.getSkuCode()));
                obj.setCheckNum(1);
                obj.setNoteId(s.getProductionOrderId());
                obj.setNoteItemId(s.getProductionOrderItemId());
                obj.setQty(s.getPlanWorkQty());
                obj.setSubmitAtName(s.getCreateAtName());
                obj.setSubmitTime(s.getCreateTime());
                return obj;
            }).collect(Collectors.toList()));
        }

        if (type != QualityTypeEnum.ProcessCheck) {
            String configValue = configureService.getValueByCode(CostCode.quality_check_proportion_by_purchase);
            result.addAll(queryCheckPlanByInventoryItem().stream().map(s -> {
                QualityCheckPlanDto obj = new QualityCheckPlanDto();
                obj.setId(s.getId());
                obj.setCode(s.getCode());
                if (s.getInventoryType() == InventoryTypeEnum.OUT) {
                    obj.setType(QualityTypeEnum.InventoryOutCheck);
                } else if (s.getInventoryType() == InventoryTypeEnum.IN) {
                    obj.setType(QualityTypeEnum.InventoryInCheck);
                } else {
                    throw new BusinessException("出入库标识不正确。");
                }
                obj.setRemark(String.format("产品编码：%s，产品名称：%s，供应商：%s", s.getSkuCode(), s.getNameAs(), s.getEntName()));
                obj.setCheckNum(1);
                obj.setNoteId(s.getNoteId());
                obj.setNoteItemId(s.getId());
                obj.setCheckPlanType(QualityCheckPlanTypeEnum.Proportion);

                if (!StringUtils.isNullOrEmpty(configValue)) {
                    obj.setCheckPlanQty(Double.valueOf(configValue));
                }
                obj.setQty(s.getQty());
                obj.setPlanCheckQty(s.getPlanCheckQty());
                obj.setSubmitAtName(s.getSubmitAtName());
                obj.setSubmitTime(s.getSubmitTime());
                return obj;
            }).collect(Collectors.toList()));
        }
        if(StringUtils.isNullOrEmpty(searchText)){
            return result.stream().sorted(Comparator.comparing(s -> s.getSubmitTime())).collect(Collectors.toList());
        }
        return result.stream().filter(s->s.getCode().contains(searchText)).sorted(Comparator.comparing(s -> s.getSubmitTime())).collect(Collectors.toList());
    }

    private List<ProductionWorkOrderExt> queryCheckPlanByProduction() {
        List<String> ids = userService.queryCurrRoles().stream().map(s -> s.getId()).collect(Collectors.toList());
        if (StringUtils.isNullOrEmpty(ids)) {
            return null;
        }
        LambdaQueryWrapper<ProductionWorkOrderExt> lq = Wrappers.lambdaQuery();
        lq.eq(ProductionWorkOrderExt::getQualityPassStatus, false);
        lq.eq(ProductionWorkOrderExt::getCompletedStatus, false);
        lq.in(ProductionWorkOrderExt::getRoleId, ids);
        return productionWorkOrderExtMapper.selectList(lq);
    }

    private List<InventoryNoteItemExt> queryCheckPlanByInventoryItem() {
        LambdaQueryWrapper<InventoryNoteItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(InventoryNoteItemExt::getQualityPassStatus, false);
        lq.eq(InventoryNoteItemExt::getAuditStatus, false);
        lq.eq(InventoryNoteItemExt::getSubmitStatus, true);
        lq.isNull(InventoryNoteItemExt::getCheckNoteId);
        lq.eq(InventoryNoteItemExt::getIsDelete, false);
        return inventoryNoteItemExtMapper.selectList(lq);
    }

    private String add(String inventoryNoteItemId, String productionWorkOrderId, String qualityDefineId, QualityTypeEnum type, String remark, Double checkQty, Double notPassQty, boolean isPass) {
        if (checkQty <= 0) {
            throw new BusinessException("检验数量不能等于零。");
        }

        QualityCheck check = new QualityCheck();
        check.setCode(String.format("QC-%s-%04d", DateUtils.formatDate(new Date(), "yyMMdd"), baseMapper.maxCode()));
        check.setInventoryNoteItemId(inventoryNoteItemId);
        check.setQualityDefineId(qualityDefineId);
        check.setQualityType(type);
        check.setRemark(remark);
        check.setCheckQty(checkQty);
        check.setNotPassQty(notPassQty == null ? 0 : notPassQty);
        check.setPassStatus(isPass);
        check.insert();

        return check.getId();
    }

    @Override
    public IPage<QualityCheckExt> query(String searchText, QualityTypeEnum type, Date startDate, Date endDate, int pageSize, int pageIndex) {
        IPage<QualityCheckExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<QualityCheckExt> lq = Wrappers.lambdaQuery();
        if (type != null && type != QualityTypeEnum.Default) {
            lq.eq(QualityCheckExt::getQualityType, type);
        }
        if (startDate != null) {
            if (endDate != null) {
                lq.gt(QualityCheckExt::getCreateTime, startDate);
                lq.lt(QualityCheckExt::getCreateTime, endDate);
            }
        }
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.eq(QualityCheckExt::getCode, searchText.trim()).or().eq(QualityCheckExt::getSkuCode, searchText.trim()).or().eq(QualityCheckExt::getOrderCode, searchText.trim());
        }
        lq.orderByDesc(QualityCheckExt::getCreateTime);
        return qualityCheckExtMapper.selectPage(page, lq);
    }
}